
#include <BFont>
#include "member_BTreeItem.h"
#include "member_BTreeWidget.h"
#include "member_BObject.h"

using namespace BWE;

member_BTreeWidget::member_BTreeWidget(BTreeWidget* treeWidget)
{
	boss = treeWidget;
	indent = 16;
	space = 2;
	selectMode = Select_Multiple | Select_Contiguous;
	arrowAlign = Align_Center;
	dirty = true;
	pressed = false;
	hoveredArrow = false;
	hoveredItem = 0;
	itemSize.set(-1, -1);
	itemAlign = Align_None;
	itemForm = Form_None;
}
member_BTreeWidget::~member_BTreeWidget()
{

}

void member_BTreeWidget::dirtyItem(BTreeItem* item)
{
	item_member(item)->dirty = true;
	BArray<BTreeItemHolder>& children = item_member(item)->children;
	for (int i = 0; i < children.size(); i++)
	{
		BTreeItem* child = children[i];
		dirtyItem(child);
	}
}
void member_BTreeWidget::freshWidget(BTreeItem* item, bool visual)
{
	if (visual && !item_member(item)->visible)
		visual = false;
	if (item_member(item)->widget)
		item_member(item)->widget->setVisible(visual);
	if (visual && !item_member(item)->expanded)
		visual = false;
	for (int i = 0; i < item_member(item)->children.size(); i++)
	{
		BTreeItem* child = item_member(item)->children[i];
		freshWidget(child, visual);
	}
}

bool member_BTreeWidget::freshArea()
{
	const BFont* font = boss->font();
	if (!font)
		return false;

	int rowHeight = font->size();
	boss->verticalScrollBar()->setStep(rowHeight);
	boss->horizontalScrollBar()->setStep(rowHeight);

	realArrowSize = arrowSize;
	if (realArrowSize.width() < 1)
		realArrowSize.width() = rowHeight / 2;
	if (realArrowSize.height() < 1)
		realArrowSize.height() = rowHeight / 2;

	int x = 0;
	int y = 0;
	BSize areaSize;
	for (int i = 0; i < topItems.size(); i++)
	{
		BTreeItem* item = topItems[i];
		freshItemRect(font, item, x, y, areaSize);
	}
	BRect area = boss->area();
	area.setSize(areaSize);
	boss->setArea(area);

	return true;
}
void member_BTreeWidget::freshItemRect(const BFont* font, BTreeItem* item, int x, int& y, BSize& areaSize)
{
	if (!item_member(item)->visible)
		return;

	const BStyle* itemStyle = boss->realStyle();
	if (item_member(item)->dirty)
		item_member(item)->freshSize(itemStyle, font, item->level() * indent);

	BSize sizeHint = item_member(item)->sizeHint;
	if (areaSize.width() < sizeHint.width())
		areaSize.width() = sizeHint.width();

	if (itemSize.width() > 0 && sizeHint.width() < itemSize.width())
		sizeHint.width() = itemSize.width();
	if (itemSize.height() > 0 && sizeHint.height() < itemSize.height())
		sizeHint.height() = itemSize.height();

	BRect rect(x, y, sizeHint.width(), sizeHint.height());
	item_member(item)->rect = rect;

	y = rect.bottom() + space;
	areaSize.height() = rect.bottom() + space;

	if (item_member(item)->expanded)
	{
		for (int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			freshItemRect(font, child, x, y, areaSize);
		}
	}
}
void member_BTreeWidget::adjustVisualItem(BTreeItem* item, const BPoint& offset, const BRect& crect)
{
	BRect rect = item_member(item)->rect + offset;
	if (rect.bottom() > crect.top() && rect.top() < crect.bottom())
	{
		item_member(item)->adjustRect(rect);
		visualItems.append(item);
	}

	if (item_member(item)->expanded)
	{
		for (int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			if (!item_member(child)->visible)
				continue;
			adjustVisualItem(child, offset, crect);
		}
	}
}
bool member_BTreeWidget::collectPrevItems(BTreeItem* item, BTreeItem* lastItem, BTreeItemList& collectedItems)
{
	while (item)
	{
		collectedItems.append(item);
		if (item == lastItem)
			return true;
		if (item->expanded())
		{
			for (int i = 0; i < item->childCount(); i++)
			{
				BTreeItem* child = item->child(i);
				if (collectPrevItems(child, lastItem, collectedItems))
					return true;
			}
		}
		item = item->prev();
	}
	return false;
}
bool member_BTreeWidget::collectNextItems(BTreeItem* item, BTreeItem* lastItem, BTreeItemList& collectedItems)
{
	while (item)
	{
		collectedItems.append(item);
		if (item == lastItem)
			return true;
		if (item->expanded())
		{
			for (int i = 0; i < item->childCount(); i++)
			{
				BTreeItem* child = item->child(i);
				if (collectNextItems(child, lastItem, collectedItems))
					return true;
			}
		}
		item = item->next();
	}
	return false;
}

void member_BTreeWidget::expandAll(BTreeItem* item)
{
	if(item)
	{
		if (!item_member(item)->expanded)
		{
			item_member(item)->expanded = false;
			this->emit(Signal_ItemExpanded, item);
		}
		for(int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			expandAll(child);
		}
	}
}
void member_BTreeWidget::shrinkAll(BTreeItem* item)
{
	if(item)
	{
		if (item_member(item)->expanded)
		{
			item_member(item)->expanded = false;
			this->emit(Signal_ItemShrinked, item);
		}
		for(int i = 0; i < item->childCount(); i++)
		{
			BTreeItem* child = item->child(i);
			shrinkAll(child);
		}
	}
}

void member_BTreeWidget::slotCountChanged(BObject* object, const BValue& value)
{
	dirty = true;
	boss->fresh();
}
